/**
 * 类组件实例对象上有那些东西
 *    - context     上下文对象，默认值是一个 空对象
 *    - props       props 数据，默认值是一个 空对象
 *    - refs        模板引用的，默认值是一个 空对象
 *    - state       state 状态数据，默认值是一个 null
 *
 * State 的概念
 *    与 props 类似，都是一个对象，state 是组件独有的数据，可以操作修改
 * State 在类组件中的创建方式
 *    一、在 构造函数中创建
 *    二、使用 public class field 语法 直接在类中定义
 * State 在类组件中的使用方式
 *    直接通过 this.state 获取
 * State 在类组件中的更新方式
 *    PS: Vue 中是实现了数据的代理或劫持，能够做到数据变化之后页面直接更新。React没有实现代理与劫持的操作，你不能直接修改 state 数据，必须通过 类原型上提供的  setState() 方法来更新 state
 
 *    注意事项：
 *    1. 不能直接修改 state。需要使用 setState
 *    2. setState 可能是异步的。（不能在setState()代码之后，立刻获取最新的state数据）
 *    3. 多次 setState 会被合并成一次。为了性能考虑只出发一次 render
 *
 * setState 的语法
 *    1. 对象语法
 *      this.setState(obj)
 *      obj 中只需要传递你需要修改的 属性。内部会使用你传递的 obj 与当前组件本身的 state 做合并，生成一个全新的对象赋值给组件的state。然后重新调用组件的 render 让组件得以更新。
 *    2. 可选的第二个参数，一个回调函数
 *      this.setState(obj, () => {
 *          // 可以通过 this 获取到最新的 state
 *      })
 *      回调函数的触发时机类似与 Vue 中 nextTick。在一轮事件循环中组件重新Render且真实DOM更新之后触发。
 *    3. 第一个参数可以写成函数形式，在函数中返回一个要修改的对象，该函数会接受到一个 newState
 *      this.setState((newState) => {
 *        return {
 *          age: newState.age + 1
 *        }
 *      })
 */

import { Component } from "react";

function fn1() {
  console.log("fn1");
  console.log(this.state.name);
}

class App extends Component {
  /**
   * 要么不写 构造函数，如果写了的化，第一行代码必须是调用父类构造函数，通过 super()
   *
   * 构造函数会收到一个 props 参数，可以使用 super(props) 传递下去
   *
   * 如果不写 super 的话，组件的this指向会出问题。
   */
  // constructor(props) {
  //   super(props);

  //   // 第一种方式：初始化 state 格式
  //   this.state = {
  //     name: "张三",
  //     age: 18,
  //   };
  // }

  // 第二种方式
  state = {
    name: "里斯",
    age: 20,
  };

  render() {
    console.log("App render", this);

    return (
      <div>
        <h1>App</h1>
        <button
          onClick={() => {
            console.log(this.state.name);
            // 尝试着修改
            // this.state.name += "~";
            // 正确做法是使用
            this.setState({
              name: this.state.name + "~",
            });
          }}
        >
          姓名：{this.state.name}
        </button>
        <button
          onClick={() => {
            this.setState(
              {
                age: this.state.age + 1,
              },
              () => {
                console.log("回调函数", this.state.age);

                console.log(document.querySelectorAll("button")[1].innerHTML);
              }
            );

            // 尝试，立刻获取最新的 age state    获取不到的
            // console.log("age", this.state.age);
          }}
        >
          年龄：{this.state.age}
        </button>
        <button
          onClick={() => {
            // 下面的代码，期望 + 5 ，但实际只 + 1 啦。这些 setState 会合并成一个，传递的对象会后续的覆盖前面的
            // this.setState({ age: this.state.age + 1 });
            // this.setState({ age: this.state.age + 1 });
            // this.setState({ age: this.state.age + 1 });
            // this.setState({ age: this.state.age + 1 });
            // this.setState({ age: this.state.age + 1 });
            // 如果希望上面代码能达到 + 5 的效果，需要换成下面的写法

            this.setState((newState) => {
              console.log("第1个", newState);
              return { age: this.state.age + 1 };
            });
            this.setState((newState) => {
              console.log("第2个", newState);
              return { age: this.state.age + 1 };
            });
            this.setState((newState) => {
              console.log("第3个", newState);
              return { age: this.state.age + 1 };
            });
            this.setState((newState) => {
              console.log("第4个", newState);
              return { age: this.state.age + 1 };
            });
            this.setState((newState) => {
              console.log("第5个", newState);
              return { age: this.state.age + 1 };
            });
          }}
        >
          年龄+ 5: {this.state.age}{" "}
        </button>
      </div>
    );
  }
}

export default App;
